<template>
  <div id="map" v-loading.fullscreen.lock="!init"></div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue';
// ol
import 'ol/ol.css';
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import XYZ from 'ol/source/XYZ.js';
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import GeoJSON from 'ol/format/GeoJSON.js';
import Style from 'ol/style/Style.js';
import Fill from 'ol/style/Fill.js';
import Stroke from 'ol/style/Stroke.js';
import Overlay from 'ol/Overlay.js';
import Draw from 'ol/interaction/Draw.js';
import Point from 'ol/geom/Point.js';
import Feature from 'ol/Feature.js';
import Icon from 'ol/style/Icon.js';
import Cluster from 'ol/source/Cluster.js';
import CircleStyle from 'ol/style/Circle.js';
import Text from 'ol/style/Text.js';
import { getDistance, getLength, getArea } from 'ol/sphere.js';

//ol-ext
import AnimatedCluster from 'ol-ext/layer/AnimatedCluster.js';

// pinia
import { useMapStore } from '@/stores/mapStore.js';

// 地图加载
const mapStore = useMapStore();
const map = ref(null);
const mapReady = ref(false); // 确保地图加载完成
const cityLayer = ref(null);

// 绘画事件
const drawType = computed(() => mapStore.drawType);
const draw = ref(null);
const drawLayer = ref(null);
const drawOverlays = ref([]);

// 标记事件
const markType = computed(() => mapStore.markType);
const markLayer = ref(null);
const markSource = ref(null);
const clusterSource = ref(null);
function getIconPath(markType) {
  switch (markType) {
    case 'ChargeStation':
      return '/ChargeStation.png';
    case 'BusStation':
      return '/BusStation.png';
    case 'ParkingLot':
      return '/ParkingLot.png';
    default:
      return '';
  }
}

// 初始化绘图交互
function initDraw() {
  drawLayer.value = new VectorLayer({
    source: new VectorSource(),
  });
  map.value.addLayer(drawLayer.value);

  draw.value = new Draw({
    source: drawLayer.value.getSource(),
    type: drawType.value,
  });
}

//初始化标记图层
function initMark() {
  // 创建原始矢量源
  markSource.value = new VectorSource();

  // 创建聚合源
  clusterSource.value = new Cluster({
    source: markSource.value,
    distance: 40,
  });

  //聚合动画是图层动画 所以直接替换图层
  markLayer.value = new AnimatedCluster({
    source: clusterSource.value,
    style: function (feature) {
      const features = feature.get('features');
      const count = features.length;
      const style = new Style();

      if (count === 1) {
        // 单个要素时使用原始图标
        const singleFeature = features[0];
        const iconSrc = singleFeature.get('icon');
        if (iconSrc) {
          style.setImage(
            new Icon({
              src: iconSrc,
              anchor: [0.5, 1],
              scale: 0.8,
            })
          );
        }
      } else {
        // 聚合要素样式
        style.setImage(
          new CircleStyle({
            radius: 10 + Math.min(Math.floor(count / 10), 10),
            stroke: new Stroke({
              color: '#fff',
              width: 2,
            }),
            fill: new Fill({
              color: '#3399CC',
            }),
          })
        );
        style.setText(
          new Text({
            text: count.toString(),
            fill: new Fill({
              color: '#fff',
            }),
            font: '12px',
          })
        );
      }
      return style;
    },
  });
  map.value.addLayer(markLayer.value);
}

const source = computed(() => {
  return new VectorSource({
    url: 'https://geo.datav.aliyun.com/areas_v3/bound/' + adCode.value + '.json',
    format: new GeoJSON(),
  });
});

const center = computed(() => mapStore.center);
const adCode = computed(() => mapStore.adCode);
const init = computed(() => mapStore.initReady);

// 初始化地图方法
function initMap() {
  map.value = new Map({
    target: 'map',
    view: new View({
      projection: 'EPSG:4326',
      center: center.value,
      zoom: 5,
    }),
    layers: [
      new TileLayer({
        source: new XYZ({
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
        }),
      }),
    ],
  });

  // 动画
  map.value.getView().animate({
    center: center.value,
    zoom: 8,
    duration: 2000,
  });

  cityLayer.value = new VectorLayer({
    source: source.value,
    style: new Style({
      fill: new Fill({
        color: 'rgba(255, 0, 0, 0.5)',
      }),
      stroke: new Stroke({
        color: '#000',
        width: 1,
      }),
    }),
  });
  map.value.addLayer(cityLayer.value);

  // overlay的点击事件
  const div = document.createElement('div');
  const overlay = new Overlay({
    element: div,
    positioning: 'left',
  });
  map.value.addOverlay(overlay);

  map.value.on('click', (e) => {
    // 绘画模式下点击事件不执行 Point Clear状态下恢复显示城市信息功能
    if (drawType.value !== 'Point' && drawType.value !== 'Clear') return;

    //只要markType不为空 且 markType不是ExitMark 就执行标记逻辑 进入绘画模式后markType.value必然为空
    if (markType.value && markType.value !== 'ExitMark') {
      console.log('当前是标记模式 点击生效');
      //创建一个点要素
      const point = new Feature({
        geometry: new Point(e.coordinate),
        icon: getIconPath(markType.value),
      });
      // 将点要素添加到原始矢量源
      markSource.value.addFeature(point);
    }
    //其他情况执行要素点击逻辑,显示城市信息
    else {
      console.log('当前是要素点击模式 点击生效');
      const feature = source.value.getFeaturesAtCoordinate(e.coordinate);
      if (feature.length > 0) {
        const props = feature[0].getProperties();
        div.innerHTML = `
        <div style="background-color: #FFC0CB; padding: 10px; width: 200px; border-radius: 5px;">
          <p>当前城市是：${props.name}</p>
          <p>经度：${center.value[0].toFixed(4)}</p>
          <p>纬度：${center.value[1].toFixed(4)}</p>
        </div>
      `;
        overlay.setPosition(center.value);
      } else {
        overlay.setPosition(undefined);
      }
    }
  });
  map.value.on('moveend', (e) => {
    // console.log('地图移动结束,当前缩放级别:', map.value.getView().getZoom());
    mapStore.setZoom(map.value.getView().getZoom());

    if (map.value.getView().getZoom() < 13) {
      cityLayer.value.setVisible(true);
    } else {
      cityLayer.value.setVisible(false);
    }
  });

  // 初始化绘图交互
  initDraw();
  initMark();
  mapReady.value = true;
  console.log('地图初始化成功');
}

onMounted(() => {
  mapStore.setDomReady(true);
});

// 初始化监听
watch(init, (newState) => {
  if (newState) {
    initMap();
  }
});

// 城市切换监听
watch(center, (newState) => {
  if (mapReady.value) {
    map.value.getView().animate({
      center: newState,
      zoom: 8,
      duration: 3000,
    });
    // 清除当前数据源
    map.value.getLayers().item(1).getSource().clear();
    // 更新数据源
    map.value.getLayers().item(1).setSource(source.value);
  }
});

// 监听drawType变化
watch(drawType, (newType) => {
  if (!mapReady.value) return; //如果地图没创建好就不执行

  map.value.removeInteraction(draw.value);
  draw.value = null;

  if (newType === 'Point') {
    return;
  } else if (newType === 'FreeHand') {
    draw.value = new Draw({
      source: drawLayer.value.getSource(),
      type: 'LineString',
      freehand: true,
    });
    map.value.addInteraction(draw.value);
  } else if (newType === 'Clear') {
    map.value.removeInteraction(draw.value);
    drawLayer.value.getSource().clear();
    drawOverlays.value.forEach((overlay) => {
      map.value.removeOverlay(overlay);
    });
    drawOverlays.value = [];
  } else if (newType === 'LineString') {
    draw.value = new Draw({
      source: drawLayer.value.getSource(),
      type: newType,
    });
    map.value.addInteraction(draw.value);
    draw.value.on('drawend', (e) => {
      //计算长度
      const feature = e.feature;
      const geometry = feature.getGeometry();
      const length = getLength(geometry, { projection: 'EPSG:4326' }) / 1000;

      //显示长度
      const div = document.createElement('div');
      div.innerHTML = `<p style="background:pink; font-size: 12px; border-radius: 3px;padding:0 5px">长度：${length.toFixed(2)}km</p>`;
      const overlay = new Overlay({
        position: geometry.getLastCoordinate(),
        element: div,
      });
      drawOverlays.value.push(overlay);
      map.value.addOverlay(overlay);
    });
  } else if (newType === 'Circle') {
    draw.value = new Draw({
      source: drawLayer.value.getSource(),
      type: newType,
    });
    map.value.addInteraction(draw.value);
    draw.value.on('drawend', (e) => {
      //计算面积
      const feature = e.feature;
      const geometry = feature.getGeometry();

      //获取圆的面积辅助函数
      function getRadiusInMeters(circle) {
        const center = circle.getCenter(); //获取圆心
        const radiusDeg = circle.getRadius(); //获取经纬度单位下的半径
        const edgePoint = [center[0] + radiusDeg, center[1]]; //获取圆边缘上的点,该点与圆心同纬度,经度=圆心经度+半径
        return getDistance(center, edgePoint);
      }

      const radius = getRadiusInMeters(geometry) / 1000;

      //显示面积
      const div = document.createElement('div');
      div.innerHTML = `<p style="background:pink; font-size: 12px; border-radius: 3px;padding:0 5px">面积：${(Math.PI * radius * radius).toFixed(
        2
      )}km²</p>`;
      const overlay = new Overlay({
        position: geometry.getLastCoordinate(),
        element: div,
      });
      drawOverlays.value.push(overlay);
      map.value.addOverlay(overlay);
    });
  } else if (newType === 'Polygon') {
    draw.value = new Draw({
      source: drawLayer.value.getSource(),
      type: newType,
    });
    map.value.addInteraction(draw.value);
    draw.value.on('drawend', (e) => {
      //计算面积
      const feature = e.feature;
      const geometry = feature.getGeometry();
      const area = getArea(geometry, { projection: 'EPSG:4326' }) / 1000000;

      //显示面积
      const div = document.createElement('div');
      div.innerHTML = `<p style="background:pink; font-size: 12px; border-radius: 3px;padding:0 5px">面积：${area.toFixed(2)}km²</p>`;
      const overlay = new Overlay({
        position: geometry.getLastCoordinate(),
        element: div,
      });
      drawOverlays.value.push(overlay);
      map.value.addOverlay(overlay);
    });
  } else {
    return;
  }
});
</script>

<style scoped>
#map {
  height: 100vh;
}
</style>
